package testJdk.nio.testSeclector.selectorServerDemo;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

/**
 * @author cyd
 * @version 1.0.0
 * @date 2021/11/24 11:15
 */

public class ServerDemo {
    public static void main(String[] args) throws Exception {
        ServerSocketChannel ssc = ServerSocketChannel.open();
        ssc.bind(new InetSocketAddress("127.0.0.1", 8000));
        ssc.configureBlocking(false);

        Selector selector = Selector.open();
        // 注册 channel，并且指定感兴趣的事件是 Accept
        ssc.register(selector, SelectionKey.OP_ACCEPT);
        ByteBuffer readBuff = ByteBuffer.allocate(1024);
        ByteBuffer writeBuff = ByteBuffer.allocate(128);

        writeBuff.put("received".getBytes());
        writeBuff.flip();

        // 轮询操作
        while (true) {
            // 阻塞到有一个通道就绪了，就继续往下执行
            selector.select();
            System.out.println("选择健满足，继续执行");
            // 获取就绪的通道的SelectionKey
            Set<SelectionKey> keys = selector.selectedKeys();
            Iterator<SelectionKey> it = keys.iterator();
            // 处理就绪的通道
            while (it.hasNext()) {
                SelectionKey key = it.next();
                it.remove();
                handleKey(selector, ssc, key, readBuff, writeBuff);
            }
        }
    }

    /**
     * 处理就绪的通道，在这个过程中，不停的有新的通道加入Selector中
     *
     * @param selector  选择器
     * @param ssc       服务端通道
     * @param key       就绪的通道的selectionKey
     * @param readBuff  输入到服务端的内容
     * @param writeBuff 输出到客户端的内容
     * @throws IOException io异常
     */
    private static void handleKey(Selector selector,
                                  ServerSocketChannel ssc,
                                  SelectionKey key,
                                  ByteBuffer readBuff,
                                  ByteBuffer writeBuff) throws IOException {
        if (key.isAcceptable()) { // 判断此密钥的通道是否准备好接受新的套接字连接
            // 创建新的连接
            SocketChannel socketChannel = ssc.accept();
            socketChannel.configureBlocking(false);
            // 把连接注册到 selector 上，并声明这个 channel 只对读操作感兴趣。
            socketChannel.register(selector, SelectionKey.OP_READ);
        } else if (key.isReadable()) {
            // 获得通道，并没有创建新的通道
            SocketChannel sc = (SocketChannel) key.channel();
            readBuff.clear();
            sc.read(readBuff);
            readBuff.flip();
            System.out.println("received:" + new String(readBuff.array()));
            // 把连接注册到 selector 上，并声明这个 channel 只对写操作感兴趣。
            key.interestOps(SelectionKey.OP_WRITE);
        } else if (key.isWritable()) {
            writeBuff.rewind();
            // 获得通道，并没有创建新的通道
            SocketChannel channel = (SocketChannel) key.channel();
            channel.write(writeBuff);
            key.interestOps(SelectionKey.OP_READ);
        }
    }
}
